﻿/**
* @description  This class serves as the base class for all UI widgets.
*/
package com.foed {
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.utils.getQualifiedClassName;

	import com.foed.managers.SkinManager;
	import com.foed.managers.StyleManager;
	import com.foed.graphic.StyleFormat;
	import com.foed.graphic.IStyleable;
	
	public class UIObject extends Sprite implements IStyleable {
		
		static public const CLASS:String = getQualifiedClassName(UIObject);

		protected var _classes:Array;
		protected var _initialized:Boolean;

		private var _styleFormat:StyleFormat;
		private var _styleFormatName:String;
		private var _width:Number;
		private var _height:Number;
		private var _skins:Object;
		
		/**
		* @description	Constructor.
		*/
		public function UIObject() {
			init();	
		}
		
		/**
		* @description	Initializes component properties.
		*/	
		protected function init():void {
			_classes = [UIObject.CLASS];
			_skins = {};
		}

		/**
		* @description	Draws component initially.
		*/	
		public function initialize():void {
			StyleManager.getInstance().style(this);
			_initialized = true;
			draw();
		}

		/**
		* @description	Creates all necessary nested graphics and components.
		*				Must be overridden by child classes.
		*/	
		protected function draw():void {
			throw new Error("draw() method must be overridden.");
		}

		/**
		* @description	Determines skin to apply based on static class properties
		*				Must be overridden by child classes.
		*
		* @params  pProp  Name of the property to look under for graphic identifier or drawing function.
		*
		* @returns  Graphic identifier or drawing function or null.
		*/
		protected final function resolveSkin(pProp:String):Class {
			return SkinManager.getInstance().getSkin(this, pProp);
		}

		/**
		* @description	Determines whether a skin has been specified on an instance level,
		*				else calls resolveSkin().
		*
		* @params  pProp  Name of the property to look under for graphic identifier or drawing function.
		*
		* @returns  Graphic identifier or drawing function or null.
		*/
		protected final function getSkin(pProp:String):Class {
			return (_skins[pProp] || resolveSkin(pProp));
		}

		/**
		* @description	Adds a listener for an event. Overridden to set useWeakReference to true.
		*
		* @param  pType  Inherited from Sprite. See AS3 docs.
		* @param  pListener  Inherited from Sprite. See AS3 docs.
		* @param  pUseCapture  Inherited from Sprite. See AS3 docs.
		* @param  pPriority  Inherited from Sprite. See AS3 docs.
		* @param  pUseWeakReference  Inherited from Sprite. See AS3 docs.
		*
		* @returns  A value of true if the event was successfully dispatched. A value of false indicates failure or that preventDefault() was called on the event.
		*/	
		override public function addEventListener(
			pType:String,
			pListener:Function,
			pUseCapture:Boolean=false,
			pPriority:int=0,
			pUseWeakReference:Boolean=true
		):void {
			super.addEventListener(pType, pListener, pUseCapture, pPriority, pUseWeakReference);
		}

		/**
		* @description	Sets the width and height of component.
		*
		* @param  pWidth  Width of component.
		* @param  pHeight  Height of component.
		*/	
		public function setSize(pWidth:Number, pHeight:Number):void {
			_width = pWidth;
			_height = pHeight;
			dispatchEvent(new Event(Event.RESIZE, true));
		}
			
		/**
		* @description	Returns styleFormat instance applied to component.
		*
		* @returns  Instance of StyleFormat applied to component.
		*/
		public function getStyleFormat():StyleFormat {
			return _styleFormat;
		}

		/**
		* @description	Sets the styleFormat instance to apply to component.
		*
		* @param  pFormat  Instance of StyleFormat to apply to component.
		*/
		public function setStyleFormat(pFormat:StyleFormat):void {
			_styleFormat = pFormat;	
		}
		
		/**
		* @description	Returns the name of the style format to be used for the component.
		*
		* @returns  String reference for styleFormat instance.
		*/
		public function getStyleFormatName():String {
			return _styleFormatName;
		}
		
		/**
		* @description	Sets the name of the style format to be used for the component.
		*
		* @param  pName  String reference for styleFormat instance.
		*/
		public function setStyleFormatName(pName:String):void {
			_styleFormatName = pName;
		}

		/**
		* @description	Removes the StyleFormat instance reference from the instance.
		*/
		public function clearStyleFormat():void {
			_styleFormat = null;
		}

		/**
		* @description  Returns the collection of classes that make up the hierarchy of the instance,
		*				preventing the need to call much more expesive functions like describeType().
		*
		* @returns  An array of strings that each hold the fully qualified name of a class.
		*/
		public function getClassHierarchy():Array {
			return _classes;
		}

		/**
		* @description  Maps a skin property to a class that will be used to draw that skin.
		*
		* @param  pKey  The name of the skin property to set the class for.
		* @param  pSkin  The class to use when drawing the skin.
		*/
		public function setSkin(pKey:String, pSkin:Class):void {
			_skins[pKey] = pSkin;
		}

		/**
		* @description  Sets all skin mapping for this instance.
		*
		* @param  pSkins  An object containing the names of this class's skin properties mapped to classes that will draw those skins.
		*/	
		public function set skins(pSkins:Object):void {
			_skins = pSkins;
		}

		/**
		* @description  Returns the width of the instance.
		*
		* @returns  The width of the instance.
		*/	
		override public function get width():Number {
			return _width;	
		}

		/**
		* @description  Prevents the setting of the width through this setter. Call setSize() instead.
		*
		* @param  pWidth  Ignored.
		*/	
		override public function set width(pWidth:Number):void {}

		/**
		* @description  Returns the height of the instance.
		*
		* @returns  The height of the instance.
		*/	
		override public function get height():Number {
			return _height;	
		}
	
		/**
		* @description  Prevents the setting of the height through this setter. Call setSize() instead.
		*
		* @param  pHeight  Ignored.
		*/	
		override public function set height(pHeight:Number):void {}

	}
	
}